#pragma once

#include <iostream>
#include <string>
#include <vector>

#include <cstring>

#include <jsoncpp/json/json.h> //引入json头文件

#include "Util.hpp"

// 协议：双方约定好的，结构化数据

// 给网络版计算器定制协议
// Request和Response都要提供 序列化 + 反序列化 的能力
// 1.自己手写
// 2.用别人写的  --- json, xml, protobuf

// #define MYSELF 1

namespace protocol_ns
{
#define SEP " "             // 分隔符
#define SEP_LEN strlen(SEP) // 不能写成sizeof
#define HEADER_SEP "\r\n"   // 报头格式
#define HEADER_SEP_LEN strlen("\r\n")

    // 请求 = 报头\r\n有效载荷\r\n
    // 响应 = 报头\r\n有效载荷\r\n
    // 报头：有效载荷的长度

    /* 给有效载荷添加报头, 形成完整的报文 */
    std::string AddHeader(const std::string &str)
    {
        std::cout << "AddHeader之前：\n"
                  << str << std::endl;

        std::string s = std::to_string(str.size());
        s += HEADER_SEP;
        s += str;
        s += HEADER_SEP;

        std::cout << "AddHeader之后：\n"
                  << s << std::endl;
        return s;
    }

    /* 给报文去除报头, 只剩下有效载荷 */
    std::string RemoveHeader(const std::string &str, int len)
    {
        std::cout << "RemoveHeader之前：\n"
                  << str << std::endl;

        std::string res = str.substr(str.size() - HEADER_SEP_LEN - len, len);

        std::cout << "RemoveHeader之后：\n"
                  << res << std::endl;
        return res;
    }

    /* 读取报文 */
    int ReadPackage(int sock, std::string &inbuffer, std::string *package)
    {
        // logMessage(DEBUG, "Start: ReadPackage....");
        std::cout << "ReadPackage 之前 inbuffer:\n"
                  << inbuffer << std::endl;

        // 边读取
        char buffer[1024];
        ssize_t s = recv(sock, buffer, sizeof(buffer), 0);
        if (s <= 0)
            return -1;

        buffer[s] = '\0';
        inbuffer += buffer;

        std::cout << "ReadPackage 之中 inbuffer:\n"
                  << inbuffer << std::endl;

        // 边分析
        size_t pos = inbuffer.find(HEADER_SEP);
        if (pos == std::string::npos)
            return 0;
        std::string lenStr = inbuffer.substr(0, pos); // 获取报头字符串
        int len = Util::toInt(lenStr);
        int targetPackageLen = lenStr.size() + len + 2 * HEADER_SEP_LEN;
        if (inbuffer.size() < targetPackageLen)
            return 0;
        *package = inbuffer.substr(0, targetPackageLen);
        inbuffer.erase(0, targetPackageLen);

        // logMessage(DEBUG, "End: ReadPackage....");

        std::cout << "ReadPackage 之后 inbuffer:\n"
                  << inbuffer << std::endl;
        return len;
    }

    class Request
    {
    public:
        Request() {}
        Request(int x, int y, char op) : _x(x), _y(y), _op(op)
        {
        }
        ~Request() {}

        // 序列化：struct->string
        // binary ---> "_x _op _y"
        bool Serialize(std::string *outStr)
        {
#ifdef MYSELF
            *outStr = "";
            std::string x_string = std::to_string(_x);
            std::string y_string = std::to_string(_y);

            *outStr = x_string + SEP + _op + SEP + y_string;

            std::cout << "Request::Serialize 之后 outStr:\n"
                      << *outStr << std::endl;
#else

            *outStr = "";
            Json::Value root; // Value : 万能对象，接受任意kv类型
            root["x"] = _x;
            root["y"] = _y;
            root["op"] = _op;

            // 序列化
            Json::FastWriter writer; //Writer是用来序列化的
            // Json::StyledWriter; //StyledWriter和FastWriter都可以，区别是前者写出的字符串的格式更好看

            *outStr = writer.write(root);

#endif
            return true;
        }

        // 反序列化：string->struct
        bool Deserialize(const std::string &inStr)
        {
#ifdef MYSELF
            // inStr: "_x _op _y"

            std::vector<std::string> result;
            Util::StringSplit(inStr, SEP, &result);

            if (result.size() != 3)
                return false;

            _x = Util::toInt(result[0]);
            _y = Util::toInt(result[2]);

            if (result[1].size() != 1)
                return false;
            _op = result[1].at(0);

            Print();
#else
            Json::Value root;
            Json::Reader reader; //Reader用来反序列化

            reader.parse(inStr, root);
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _op = root["op"].asInt();

#endif
            return true;
        }

        void Print()
        {
            std::cout << "_x: " << _x << "\n";
            std::cout << "_y: " << _y << "\n";
            std::cout << "_op: " << _op << "\n";
        }

    public:
        // _x _op _y
        int _x;
        int _y;
        char _op;
    };

    class Response
    {
    public:
        Response() {}
        Response(int result, int code) : _result(result), _code(code)
        {
        }
        ~Response() {}

        // 序列化：struct->string
        // binary: _result _code
        bool Serialize(std::string *outStr)
        {
#ifdef MYSELF
            *outStr = "";
            std::string res_string = std::to_string(_result);
            std::string code_string = std::to_string(_code);
            *outStr = res_string + SEP + code_string;

            std::cout << "Response::Serialize 之后 outStr:\n"
                      << *outStr << std::endl;
#else

            *outStr = "";
            Json::Value root;
            root["result"] = _result;
            root["code"] = _code;
            Json::FastWriter writer;
            *outStr = writer.write(root);

#endif
            return true;
        }

        // 反序列化：string->struct
        bool Deserialize(const std::string &inStr)
        {
#ifdef MYSELF
            // inStr: "_result _code"
            std::vector<std::string> result;
            Util::StringSplit(inStr, SEP, &result);
            if (result.size() != 2)
                return false;
            _result = Util::toInt(result[0]);
            _code = Util::toInt(result[1]);

            Print();
#else
            Json::Value root;
            Json::Reader reader;
            reader.parse(inStr, root);
            _result = root["result"].asInt();
            _code = root["code"].asInt();

#endif
            return true;
        }

        void Print()
        {
            std::cout << "_result: " << _result << "\n";
            std::cout << "_code: " << _code << "\n";
        }

    public:
        int _result;
        int _code; // 0:success ; 1,2,3,4...代表不同错误码
    };
}